package edu.maping.easy.minim;

import processing.core.PApplet;
import controlP5.ControlEvent;
import controlP5.ControlP5;
import ddf.minim.AudioPlayer;
import ddf.minim.Minim;
import ddf.minim.analysis.FFT;
import edu.maping.easy.ControlFacade;
import edu.maping.easy.gui.GuiFactory;
import edu.maping.easy.model.EasyMappingPlugin;
import edu.maping.easy.model.Thing;
import edu.maping.easy.model.World;
import edu.maping.easy.sequence.EasyMappingTimeTicker;

public class MinimPlugin implements EasyMappingPlugin, FFTFacade {

	Minim minim;
	AudioPlayer jingle;
	FFT fft;

	private static int AVG_SIZE = 20;

	float avgs[] = null;
	float maxAvgs[] = null;
	long sizeAvgs = 0;

	private EasyMappingTimeTicker timeTicker = null;

	@Override
	public void setup(PApplet pApplet) {
		minim = new Minim(pApplet);

		jingle = minim.loadFile("11.mp3", 2048);
		// loop the file
		// create an FFT object that has a time-domain buffer the same size as
		// jingle's sample buffer
		// and a sample rate that is the same as jingle's
		// note that this needs to be a power of two
		// and that it means the size of the spectrum will be 1024.
		// see the online tutorial for more info.
		fft = new FFT(jingle.bufferSize(), jingle.sampleRate());
		// use 128 averages.
		// the maximum number of averages we could ask for is half the spectrum
		// size.
		fft.linAverages(AVG_SIZE);
		fft.window(FFT.HAMMING);

		avgs = new float[AVG_SIZE];
		for (int i = 0; i < AVG_SIZE; i++) {
			avgs[i] = 0;
		}

		maxAvgs = new float[AVG_SIZE];
		for (int i = 0; i < AVG_SIZE; i++) {
			maxAvgs[i] = 0;
		}
	}

	@Override
	public void draw(PApplet pApplet) {
		// pApplet.background(0);
		pApplet.stroke(255);
		// perform a forward FFT on the samples in jingle's left buffer
		// note that if jingle were a MONO file, this would be the same as using
		// jingle.right or jingle.left
		fft.forward(jingle.mix);
		int w = (int) (fft.specSize() / 128);
		pApplet.stroke(255);
		for (int i = 0; i < fft.avgSize(); i++) {
			// draw a rectangle for each average, multiply the value by 5 so we
			// can see it better
			pApplet.rect(i * w, pApplet.height, i * w + w, pApplet.height
					- fft.getAvg(i) * 5);
		}
		pApplet.fill(255);
		// keep us informed about the window being used
		// text("The window being used is: " + windowName, 5, 20);

		boolean[] triggers = updateAVGs(fft);
		pApplet.stroke(255, 0, 0, 128);
		for (int i = 0; i < AVG_SIZE; i++) {
			pApplet.rect(i * w, pApplet.height, i * w + w, pApplet.height
					- (avgs[i] / sizeAvgs) * 5);
		}

		// RNDER MAXAVG
		pApplet.stroke(255, 255, 0);
		for (int i = 0; i < AVG_SIZE; i++) {
			float value = pApplet.height - (maxAvgs[i]) * 5;
			pApplet.rect(i * w, value - 3, i * w + w, value);
		}

		// TRIGGER

		int countTrigger = 0;

		for (int index = 0; index < AVG_SIZE; index++) {
			boolean b = triggers[index];
			if (b) {
				countTrigger++;
				doTrigger(index);
			}
		}
	}

	private void doTrigger(int index) {
		if (index == 1)
			timeTicker.tick();
	}

	private boolean[] updateAVGs(FFT fft) {
		for (int i = 0; i < AVG_SIZE; i++) {
			avgs[i] += fft.getAvg(i);
		}
		sizeAvgs++;

		boolean[] triggers = new boolean[AVG_SIZE];
		for (int i = 0; i < AVG_SIZE; i++) {
			float currentAvg = fft.getAvg(i);
			float currentMaxAvg = maxAvgs[i];
			if (currentAvg > currentMaxAvg) {
				maxAvgs[i] = currentAvg;
				triggers[i] = true;
			} else if (currentAvg != 0) {
				maxAvgs[i] = currentMaxAvg - 0.15F;
				triggers[i] = false;
			}
		}

		return triggers;
	}

	@Override
	public void stop(World world, PApplet pApplet, ControlP5 controlP5) {
		// TODO Auto-generated method stub
		jingle.pause();
	}

	@Override
	public String getName() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setParameters(Thing thing) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setup(PApplet pApplet, GuiFactory guiFactory) {
		// TODO Auto-generated method stub

	}

	@Override
	public void start(World world, PApplet pApplet, ControlP5 controlP5) {
		// TODO Auto-generated method stub
		jingle.loop();
	}

	public void setTimeTicker(EasyMappingTimeTicker timeTicker) {
		this.timeTicker = timeTicker;
	}

	public FFT getFft() {
		return fft;
	}

}
